﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;

namespace BaiduMapTileCutter.GaoDe
{
   public  class GaoDeCuttle
    {
        double maxExtentLeft = -2.00375e+007;
        double maxExtentTop = 2.00375e+007;
        /// <summary>
        /// 地图精度(分辨率)
        /// </summary>
        double[] resolution =
            new double[]
            {
                    156543.033928,          //0+1
                    78271.5169639999,       //1+1
                    39135.7584820001,       //2+1
                    19567.8792409999,       //3+1
                    9783.93962049996,       //4+1
                    2445.98490512499,       //5+1
                    1222.99245256249,       //6+1
                    611.49622628138,        //7+1
                    305.748113140558,       //8+1
                    152.874056570411,       //9+1
                    76.4370282850732,       //10+1
                    38.2185141425366,       //11+1
                    19.1092570712683,       //12+1
                    9.55462853563415,       //13+1
                    4.77731426794937,       //14+1
                    2.388657133483887f,//  2.388657133483887     //15+1
                    1.1943285667419434f,     //16+1
                    0.5971642833709717f,     //17+1
                    0.298582141647617f       //18+1
            };


        private string outputPath;
        private OutputFileTypes outputFileType;
        private LatLng center;
        private ZoomInfo zoomInfo;

        private Bitmap tileImage;


        private int totalCount = 0;
        private int finishCount = 0;

        private int iWidth;

        private int iHeight;

        string fname;


        public int GetFinishCount()
        {
            return finishCount;
        }

        public int GetTotalCount()
        {
            return totalCount;
        }

        public void SetInfo(string imgPath, string outputPath, OutputFileTypes outputFileType, LatLng center,
            ZoomInfo zoomInfo,Int32 titIWidth,Int32 titIHeight,String fnameFormat)
        {
            this.outputPath = outputPath;
            this.outputFileType = outputFileType;
            this.center = center;
            this.zoomInfo = zoomInfo;
            tileImage = new Bitmap(imgPath);
            this.iWidth = titIWidth;
            this.iHeight = titIHeight;
            this.fname = fnameFormat;

        }


        public void StartCut()
        {                  
            beginCut();
            if (outputFileType == OutputFileTypes.TileAndCode)
            {
                //generateHTMLFile();
            }
            tileImage.Dispose();
        }

        public void beginCut()
        {           
            try
            {
               

                // 加载图片

                /**
                 * 计算总量
                 */
                totalCount = (zoomInfo.MaxZoom - zoomInfo.MinZoom) * (tileImage.Height / iWidth + 1)*(tileImage.Width / iHeight + 1);

                for (int i = zoomInfo.MinZoom; i <= zoomInfo.MaxZoom; i++)
                {
                    Size newSize = new Size();
                    double num2 = Math.Pow(2.0, (double)(zoomInfo.ImageZoom - i));

                    newSize.Height = (int)(((double)tileImage.Height) / num2);
                    newSize.Width = (int)(((double)tileImage.Width) / num2);

                    if ((newSize.Width != 0) && (newSize.Height != 0))
                    {
                        Bitmap bitmap2 = new Bitmap(tileImage, newSize);
                        string filename = this.outputPath + "/temp" + i + ".png";
                        bitmap2.Save(filename);

                        this.CutImages(filename, i);
                        bitmap2.Dispose();
                        try
                        {
                            File.Delete(this.outputPath + "/temp" + i + ".png");
                        }
                        catch { }
                    }

                }
              
            }
            finally
            {
               
            }
        }


        /// <summary>
        /// 执行切图操作
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="zoom"></param>
        private void CutImages(string fileName, int zoom)
        {


            //取得顶点
            BMap.Point point = ConvertPoint(center.Lat, center.Lng, zoom);

            int iLeft = 0, iTop = 0;
            // 加载图片

            for (int i = 0; i < tileImage.Height / iWidth + 1; i++)
            {
                iTop = i * iWidth;
                for (int j = 0; j < tileImage.Width / iHeight + 1; j++)
                {
                    iLeft = j * iHeight;

                    // 目标区域
                    Rectangle destRect = new Rectangle(0, 0, iWidth, iHeight);
                    // 源图区域
                    Rectangle srcRect = new Rectangle(iLeft, iTop, iWidth, iHeight);

                    // 新建Graphics对象
                    Bitmap newImage = new Bitmap(iWidth, iHeight);
                    Graphics g = Graphics.FromImage(newImage);

                    // 绘图平滑程序
                    g.SmoothingMode = SmoothingMode.HighQuality;

                    // 图片输出质量
                    g.CompositingQuality = CompositingQuality.HighQuality;

                    // 输出到newImage对象
                    g.DrawImage(tileImage, destRect, srcRect, GraphicsUnit.Pixel);

                    // 释放绘图对象
                    g.Dispose();

                    //如果文件不存在
                    if (!Directory.Exists(outputPath + "\\" + zoom))
                    {
                        Directory.CreateDirectory(outputPath + "\\" + zoom);
                    }
                    string strDestFile = string.Format(outputPath + @"\" + zoom + @"\" + @fname + ".png", (point.X + j),
                        (point.Y + i));

                    newImage.Save(strDestFile, ImageFormat.Png);

                    float finished = (i * (tileImage.Height / iWidth + 1) + j + 1) * 10000;
                    float total = ((tileImage.Height / iWidth) * (tileImage.Width / iHeight)) * 100;
                    float result = finished / total;

                    finishCount++;
                }

            }
        }


        /// <summary>
        /// （内部换算，核心）将经纬度按照缩放值转换成坐标点
        /// </summary>
        /// <param name="lat"></param>
        /// <param name="lng"></param>
        /// <param name="zoom"></param>
        /// <returns></returns>
        public BMap.Point ConvertPoint(double lat, double lng, int zoom)
        {

            //        var loc1:*=0.00449797741722;
            //var loc2:*=0.00213;
            //16级为基准，17级的lat不变
            //与16级相比,17级与16级相比，lng需要调整，lat不需要调整
            if (zoom == 17)
            {
                lng += 0.00274;
            }
            if (zoom == 18)
            {
                lng += 0.00274;
                //lng = lng;// +0.00136;//120.???
                lat = lat + 0.00117;//31.??
            }




            BMap.Point p = LngLatToMercator(lng, lat); ;// new BMap.GoogleMapsProjection().fromLatLngToPoint(lat, lng, zoom);// LngLatToMercator(lng, lat);

            //BMap.Point p2 = LngLatToMercator(lng, lat);
            //BMap.Point p3 = new BMap.GoogleMapsProjection().MCT84Bl2xy(lng, lat);

            //地图的分辨率
            double res = resolution[zoom - 1];

            double originTileX = Math.Round((p.X - this.maxExtentLeft) / (res * Convert.ToDouble(iWidth)));
            double originTileY = Math.Round((this.maxExtentTop - p.Y) / (res * Convert.ToDouble(iHeight)));

            double zoomPower = Math.Pow(2, zoom);

            if (originTileY < 0 || originTileY >= zoomPower || originTileX < 0 || originTileX >= zoomPower)
            {
                return null;
            }

            originTileX = (originTileX % zoomPower + zoomPower) % zoomPower;
            originTileY = (originTileY % zoomPower + zoomPower) % zoomPower;

            return new BMap.Point(originTileX, originTileY);


        }


        //像素X到经度  
        public static double pixelToLng(double pixelX, int zoom)
        {
            return pixelX * 360 / (256 * 2 ^ zoom) - 180;
        }


        //经度到像素
        public double lngToPixel(double lng, int zoom)
        {
            return (lng + 180) * (256L << zoom) / 360;
        }

        //纬度到像素Y
        public double latToPixel(double lat, int zoom)
        {
            double siny = Math.Sin(lat * Math.PI / 180);
            double y = Math.Log((1 + siny) / (1 - siny));
            return (128 << zoom) * (1 - y / (2 * Math.PI));
        }



        /// <summary>
        /// 经纬度转换成坐标值
        /// </summary>
        /// <param name="lon"></param>
        /// <param name="lat"></param>
        /// <returns></returns>
        public BMap.Point LngLatToMercator(double lon, double lat)
        {

            //            var loc1:*=0.00449797741722;
            //var loc2:*=0.00213;
            lon = lon + 0.00449797741722;
            lat = lat - 0.00213;
            double x = lon * 20037508.34 / 180;
            double y = -180;
            if (lat > -90)
                y = Math.Log(Math.Tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);

            y = y * 20037508.34 / 180;

            //double x = latToPixel(lat,zoom);
            //double y = lngToPixel(lon,zoom);

            return new BMap.Point(x, y);

        }
    }
}
